#include "StdAfx.h"
#include <map>
#include "Frame.hxx"
#include "StreamSynchronizer.hxx"
#include "ProcessStream.hxx"
#include "PipeLine.hxx"
#include "FrameArray.hxx"


StreamSynchronizer::StreamSynchronizer(PipeLine* pipeLine):_pipeLine(pipeLine)
{
	_isStopped = true;
	_nextSyncedIndex = 0;

	::InitializeCriticalSection( &_syncCs );
}


StreamSynchronizer::~StreamSynchronizer(void)
{
}


DWORD WINAPI SynchronizeProc(LPVOID lpParam)
{
	StreamSynchronizer* synchronizer = (StreamSynchronizer*)lpParam;

	while( !synchronizer->isStopped() )
	{
		synchronizer->execute();
	}
	return 0;
}


void StreamSynchronizer::start()
{
	_isStopped = false;
	
	DWORD dwThreadID = 0;
	
	CreateThread( NULL, 0, SynchronizeProc, this, 0, &dwThreadID );
}

void StreamSynchronizer::execute()
{
	if( _syncedFrames.size() > 0 )
	{   
		lock();

		SyncFrame* syncFrame = _syncedFrames.front();

		bool handled = true;

		for( int i = 0; i < CHANNEL_COUNT; i ++ )
		{
			if( syncFrame->StreamedFrames[ i ]->ProcessStepFlag != STEP_SYNCRONIZE )
			{
				handled = false;
				break;
			}
		}

		if( handled )
		{
			for( int i = 0; i < CHANNEL_COUNT; i ++)
				getPipeLine()->getProcessStream( i )->getFrameArray()->eraseFrameByIndex( syncFrame->StreamedFrames[ i ]->StoreIndex );
			
			_syncedFrames.pop();
			delete syncFrame;
		}
		
		unlock();
	}
	else
	{
		Sleep( 30 );
	}

	
}

void StreamSynchronizer::initialize()
{
}

void StreamSynchronizer::synchronizeFrame( int channelIndex, Frame* frame )
{
	lock();

	if( _unSyncArray[ channelIndex ].size() > 0 )
	{
		SyncFrame* syncFrame = _unSyncArray[ channelIndex ].front();
		syncFrame->StreamedFrames[ channelIndex ] = frame;
		_unSyncArray[ channelIndex ].pop();

		bool synced = true;
		for( int i = 0; i < CHANNEL_COUNT; i ++ )
		{
			if( !syncFrame->StreamedFrames[ i ] )
			{
				synced = false;
				break;
			}
		}

		if( synced )
		{
			syncFrame->Synchronized = true;
			_syncedFrames.push( syncFrame );

			printf("Synchronized Frame %d\n", syncFrame->Index);
		}
	}
	else
	{
		SyncFrame* syncFrame = new SyncFrame();
		syncFrame->Index = _nextSyncedIndex++;
		syncFrame->StreamedFrames[ channelIndex ] = frame;

		for( int i = 0; i < CHANNEL_COUNT; i ++ )
		{
			if( i != channelIndex )
				_unSyncArray[ i ].push( syncFrame );
		}
	}

	unlock();
}

void StreamSynchronizer::lock()
{
	::EnterCriticalSection( &_syncCs );
}

void StreamSynchronizer::unlock()
{
	::LeaveCriticalSection( &_syncCs );
}